package sun.scheduler.gui;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * Holds a {
 * 
 * @see List of {
 * @see Point 's and some basic gui properties that represent a visual curve
 *      object.
 * @author mfj
 */
public class Curve implements Scalable {
    
        private String curveName = "";
	private ArrayList<Point> coordinates;

	private Color color = Color.BLACK;
	private Color nodeColor = Color.GRAY;

	private double thickness = 1;

	private double scaleX = 1;

	private double scaleY = 1;
        
        private int offsetX, offsetY, height;
        
        private float maxX, maxY, minX, minY;
        private int radius = 10;

	public Curve(ArrayList<Point> coordinates) {
		this.coordinates = coordinates;
	}

	public Curve(ArrayList<Point> coordinates, Color color, Color nodeColor, double thickness) {
		this.coordinates = coordinates;
		this.color = color;
		this.nodeColor = nodeColor;
		this.thickness = thickness;
	}
	
	public Curve(Curve curve) {
		this.coordinates = curve.getCoordinates();
		this.color = curve.getColor();
		this.thickness = curve.getThickness();
		this.color = curve.getColor();
		this.nodeColor = curve.getNodeColor();
		this.scaleX = curve.getScaleX();
		this.scaleY = curve.getScaleY();
	}
	

	public Curve clone() {
		Curve curve = new Curve(coordinates);
		curve.setColor(color);
		curve.setThickness(thickness);
		curve.setColor(color);
		curve.setScaleX(scaleX);
		curve.setScaleY(scaleY);
		curve.setNodeColor(nodeColor);
		return curve;
	}
        public String getName() {
            return curveName;
        }
        
        public void setName(String name) {
            curveName = name;
        }
	
	private Color getNodeColor() {
		return nodeColor;
	}

	private void setNodeColor(Color nodeColor) {
		this.nodeColor = nodeColor;
		
	}

	public Color getColor() {
		return color;
	}

	public void setColor(Color color) {
		this.color = color;
	}

	public double getThickness() {
		return thickness;
	}

	public void setThickness(double thickness) {
		this.thickness = thickness;
	}

	public ArrayList<Point> getCoordinates() {
		return coordinates;
	}
        
        private double scaledX(double x) {
            
            return (x -minX) * (scaleX) +offsetX;
        }
        
        private double scaledY(double y) {
            return height-(y-minY) * scaleY-offsetY;
        }

	/**
	 * Draws this curve to the graphics element.
	 * 
	 * @param g2d
	 * @param offsetX
	 * @param offsetY
	 */
	public void draw(Graphics2D g2d, int offsetX, int offsetY, int height,int width, float maxY, float maxX, float minY, float minX) {
		g2d.setColor(color);
                int cap = BasicStroke.CAP_BUTT;
                int join = BasicStroke.JOIN_MITER;
                this.offsetX = offsetX;
                this.offsetY = offsetY;
                this.height = height;
                this.minX = minX;
                this.minY = minY;
                this.maxX = maxX;
                this.maxY = maxY;
                BasicStroke stroke = new BasicStroke((float)thickness,cap,join);
                g2d.setStroke(stroke);
		ArrayList<Point> orderedCoords = new ArrayList<Point>();
		orderedCoords.addAll(coordinates);
		Collections.sort(orderedCoords, new Comparator<Point>() { // compare x's
					@Override
					public int compare(Point o1, Point o2) {
						Integer x1 = new Integer(o1.x);
						Integer x2 = new Integer(o2.x);
						return x1.compareTo(x2);
					}
				});
		int almostSize = orderedCoords.size() - 1;
	
		g2d.setColor(color); // set line color
                for (int i = 0; i < almostSize; i++) { // draw LINES first
                        
			Point p1 = new Point();
			Point p2 = new Point();
			p1.setLocation(scaledX(orderedCoords.get(i).getX()), scaledY(orderedCoords
					.get(i).getY()));
			p2.setLocation(scaledX(orderedCoords.get(i + 1).getX()),
					scaledY(orderedCoords.get(i + 1).getY() ));
                        
			g2d.draw(new Line2D.Float(p1, p2));
                        
		}
                
                g2d.setColor(nodeColor); // set node color
                for (int i = 0; i < almostSize; i++) { // draw NODES after
                        
			Point p1 = new Point();
			Point p2 = new Point();
			p1.setLocation(scaledX(orderedCoords.get(i).getX()), scaledY(orderedCoords
					.get(i).getY()));
			p2.setLocation(scaledX(orderedCoords.get(i + 1).getX()),
					scaledY(orderedCoords.get(i + 1).getY() ));
                        
                        Ellipse2D eli = new Ellipse2D.Float((float)(p1.x - radius/2.0), (float)(p1.y - radius/2.0), radius, radius);
			//if(i!=0) { // skip first node!!!
                        g2d.draw(eli);
                        g2d.fill(eli);
                        //}
                        if(i==almostSize-1) { //Paint last node and color it different
                            g2d.setColor(Color.DARK_GRAY);
                            eli = new Ellipse2D.Float((float)(p2.x - radius/2.0), (float)(p2.y - radius/2.0), radius, radius);
                            g2d.draw(eli);
                            g2d.fill(eli);
                        }
		}
                g2d.setStroke(new BasicStroke(1,cap,join));
               
	}

	@Override
	public void setScaleX(double value) {
		if (value <= 0)
			throw new IllegalArgumentException();

		if (scaleX == value)
			return;

		scaleX = value;
	}

	@Override
	public void setScaleY(double value) {
		if (value <= 0)
			throw new IllegalArgumentException();

		if (scaleY == value)
			return;

		scaleY = value;
	}

	@Override
	public double getScaleX() {
		return scaleX;
	}

	@Override
	public double getScaleY() {
		return scaleY;
	}

}
